home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************
- * Send.c: File transmission routines for xprzmodem.library;
- * Original Version 2.10, 12 February 1991, by Rick Huebner.
- * Based closely on Chuck Forsberg's sz.c example ZModem code,
- * but too pervasively modified to even think of detailing the changes.
- * Released to the Public Domain; do as you like with this code.
- *
- * Version 2.50, 15 November 1991, CRC-32 additions by William M. Perkins.
- * Version 2.51 29, January 1992, RX_timout fix by John Tillema
- * Version 2.52 6 March 1992, Very minor fix with compiled 020 library
- * by William M. Perkins.
- * Version 2.53, 28 June 1993, several additions by Olaf `Olsen' Barthel
- **********************************************************************/
-
- /* Convert decimal to octal value. */
- STATIC VOID __regargs
- to_octal(STRPTR buf, ULONG value)
- {
- UBYTE buffer[20];
- register short i = 1;
-
- while (value)
- {
- buffer[i++] = '0' + (value & 7);
-
- value >>= 3;
- }
-
- do
- *buf++ = buffer[--i];
- while (i);
-
- *buf = 0;
- }
-
- /**********************************************************
- * long XProtocolSend(struct XPR_IO *xio)
- *
- * Main file transmission routine; called by comm program
- **********************************************************/
- long __saveds __asm XProtocolSend(register __a0 struct XPR_IO *xio)
- {
- struct Vars *v;
- short err;
-
- /* Perform common setup and initializations */
- if (!(v = setup(xio)))
- return XPRS_FAILURE;
-
- /* was 600, set to 300 to fix so it uploads correctly */
- v->Rxtimeout = 300;
- v->Wantfcs32 = TRUE;
- v->Rxflags = 0;
- v->Receiving = FALSE;
-
- /* Transfer the files */
- zmputs(v, "rz\r");
- stohdr(v, 0L);
- zshhdr(v, ZRQINIT);
- sendbuf(v);
- if (getzrxinit(v) == ERROR)
- upderr(v, GetLocaleString(MSG_UPLOAD_CANCELED_TXT));
- else
- sendbatch(v);
-
- /* Clean up and return */
- if (err = v->Errcnt)
- upderr(v, GetLocaleString(MSG_FILES_SKIPPED_DUE_TO_ERRORS_TXT));
- else
- updmsg(v, GetLocaleString(MSG_DONE_TXT));
- if (v->io.xpr_setserial && v->Oldstatus != -1)
- (*v->io.xpr_setserial) (v->Oldstatus);
- FreeMem(v->Filebuf, v->Filebufmax);
- FreeMem(v, (long) sizeof(struct Vars));
-
- return (err) ? XPRS_FAILURE : XPRS_SUCCESS;
- } /* End of long XProtocolSend() */
-
- /**********************************************************
- * short getzrxinit(struct Vars *v)
- *
- * Negotiate with receiver to start a file transfer
- **********************************************************/
- short getzrxinit(struct Vars *v)
- {
- short n;
-
- for (n = v->ErrorLimit; --n >= 0;)
- {
- /* Check for abort from comm program */
- if (v->io.xpr_chkabort && (*v->io.xpr_chkabort) () < 0)
- {
- canit(v); /* Receiver does not respond to ZABORT. */
- return ERROR;
- }
- switch (zgethdr(v))
- {
- case ZCHALLENGE: /* Echo receiver's challenge number */
- stohdr(v, v->Rxpos);
- zshhdr(v, ZACK);
- sendbuf(v);
- continue;
- case ZCOMMAND: /* They didn't see our ZRQINIT; try again */
- stohdr(v, 0L);
- zshhdr(v, ZRQINIT);
- sendbuf(v);
- continue;
- case ZRINIT: /* Receiver ready; get transfer parameters */
- v->Rxflags = 0xFF & v->Rxhdr[ZF0];
- v->Txfcs32 = (v->Wantfcs32 && (v->Rxflags & CANFC32));
- v->Zctlesc |= v->Rxflags & TESCCTL;
- v->Rxbuflen = ((USHORT) v->Rxhdr[ZP1] << 8) | v->Rxhdr[ZP0];
- /* Use shortest of the two side's max frame lengths */
- if (v->Tframlen && (!v->Rxbuflen || v->Tframlen < v->Rxbuflen))
- v->Rxbuflen = v->Tframlen;
- return (sendzsinit(v));
- case ZCAN:
- case RCDO:
- case TIMEOUT:
- upderr(v, v->Msgbuf);
- return ERROR;
- case ZRQINIT:
- if (v->Rxhdr[ZF0] == ZCOMMAND)
- continue;
- /* fallthrough... */
- default:
- zshhdr(v, ZNAK);
- sendbuf(v);
- continue;
- }
- }
- return ERROR;
- } /* End of short getzrxinit() */
-
- /* Send send-init information */
- short sendzsinit(struct Vars *v)
- {
- if (v->Attn[0] == '\0' && (!v->Zctlesc || (v->Rxflags & TESCCTL)))
- return OK;
- else
- {
- register short c, errors = 0;
-
- for (;;)
- {
- stohdr(v, 0L);
- if (v->Zctlesc)
- {
- v->Txhdr[ZF0] |= TESCCTL;
- zshhdr(v, ZSINIT);
- }
- else
- zsbhdr(v, ZSINIT);
-
- v->Outbuf[0] = 0;
- zsdata(v, 1, ZCRCW);
-
- c = zgethdr(v);
- switch (c)
- {
- case ZCAN:
- return ERROR;
- case ZACK:
- return OK;
- default:
- if (++errors > v->ErrorLimit)
- return ERROR;
- continue;
- }
- }
- }
- } /* End of short sendzsinit() */
-
- /**********************************************************
- * void sendbatch(struct Vars *v)
- *
- * Send a batch of files
- **********************************************************/
- void sendbatch(struct Vars *v)
- {
- UBYTE single, done = FALSE;
- long fstate;
-
- /* If template routines not provided, must be single filename */
- if (!v->io.xpr_ffirst || !v->io.xpr_fnext)
- {
- single = TRUE;
- strcpy(v->Filename, v->io.xpr_filename);
- /* Else use the template routines to get the first filename */
- }
- else
- {
- single = FALSE;
- fstate = (*v->io.xpr_ffirst) (v->Filename, v->io.xpr_filename);
- if (!fstate)
- {
- upderr(v, GetLocaleString(MSG_NO_FILES_MATCH_TEMPLATE_TXT));
- return;
- }
- }
-
- /* If using templates, keep getting names & sending until done */
- while (!done)
- {
- if (sendone(v) == ERROR)
- return;
- if (single)
- break;
- fstate = (*v->io.xpr_fnext) (fstate, v->Filename, v->io.xpr_filename);
- done = !fstate;
- }
-
- /* End batch and return; if we never got started, just cancel receiver */
- if (v->Filcnt)
- saybibi(v);
- else
- canit(v);
- } /* End of void sendbatch() */
-
- /**********************************************************
- * short sendone(struct Vars *v)
- *
- * Send the file named in v->Filename
- **********************************************************/
- short sendone(struct Vars *v)
- {
- struct SetupVars *sv;
-
- /* Display name of file being sent for user */
- v->xpru.xpru_updatemask = XPRU_FILENAME;
- v->xpru.xpru_filename = v->Filename;
- (*v->io.xpr_update) (&v->xpru);
-
- /* Set text/binary mode according to options before opening file */
- set_textmode(v);
-
- /* Open the file, if possible */
- if (!(v->File = bfopen(v, "r")))
- {
- ++v->Errcnt;
- upderr(v, GetLocaleString(MSG_CANT_OPEN_FILE_TXT));
- return OK; /* pass over it, there may be others */
- }
- ++v->Filcnt;
- GetSysTime(&v->Starttime);
- v->BytesSent = 0;
-
- /* Kick off the file transfer */
- sv = (void *) v->io.xpr_data;
- switch (sendname(v))
- {
- case ERROR:
- ++v->Errcnt;
- return ERROR;
- case OK:
- bfclose(v);
- /* File sent; if option DY, delete file after sending */
- if (*sv->option_d == 'Y' && v->io.xpr_extension >= 2 && v->io.xpr_unlink)
- {
- updmsg(v, GetLocaleString(MSG_DELETING_FILE_AFTER_SEND_TXT));
- (*v->io.xpr_unlink) (v->Filename);
- }
- break;
- }
- return OK;
- } /* End of short sendone() */
-
- /**********************************************************
- * short sendname(struct Vars *v)
- *
- * Build file info block consisting of file name, length,
- * time, and mode
- **********************************************************/
- short sendname(struct Vars *v)
- {
- struct SetupVars *sv;
- UBYTE *p, *q, buff[32], mode[5];
- BPTR FileLock;
-
- /* Initialize comm program transfer status display */
- v->Fsize = (v->io.xpr_finfo) ? (*v->io.xpr_finfo) (v->Filename, 1L) : -1;
- v->xpru.xpru_updatemask = XPRU_PROTOCOL | XPRU_FILESIZE | XPRU_MSG
- | XPRU_BLOCKS | XPRU_ERRORS | XPRU_TIMEOUTS | XPRU_BLOCKCHECK
- | XPRU_BYTES | XPRU_ELAPSEDTIME;
- v->xpru.xpru_protocol = "ZModem";
- v->xpru.xpru_filesize = v->Fsize;
- v->xpru.xpru_msg = (v->Lzconv == ZCNL) ? GetLocaleString(MSG_SENDING_TEXT_FILE_TXT) :
- ((v->Lzconv == ZCBIN) ? GetLocaleString(MSG_SENDING_BINARY_FILE_TXT) : GetLocaleString(MSG_SENDING_FILE_TXT));
- v->xpru.xpru_blocks = v->xpru.xpru_errors = v->xpru.xpru_timeouts = 0;
- v->xpru.xpru_blockcheck = v->Crc32t ? "CRC-32" : "CRC-16";
- v->xpru.xpru_bytes = v->Strtpos = 0;
- v->xpru.xpru_blocksize = v->ksize;
- update_rate(v);
- (*v->io.xpr_update) (&v->xpru);
-
- sv = (void *) v->io.xpr_data;
- if (*sv->option_s == 'Y')
- {
- /* If "SY" option selected, send full path */
- strcpy(v->Pktbuf, v->Filename);
- p = v->Pktbuf + strlen(v->Pktbuf) + 1;
- }
- else
- {
- /* else extract outgoing file name without directory path */
- for (p = v->Filename, q = v->Pktbuf; *p; ++p, ++q)
- if ((*q = *p) == '/' || *q == ':')
- q = v->Pktbuf - 1;
- *q = '\0';
- p = ++q;
- }
-
- /* Zero out remainder of file info packet */
- memset(p, 0, sizeof(v->Pktbuf) - (p - v->Pktbuf));
-
- /* Store file size, timestamp, and mode in info packet */
- if (v->FileAttributes & 1)
- {
- ULONG Seconds = getsystime(NULL), Mode = 0000; /* owner = rwx, group = rwx, others = rwx */
-
- /* See if we can lock it, this probably won't work for `term'. */
- if (FileLock = Lock(v->Filename, ACCESS_READ))
- {
- struct FileInfoBlock __aligned FileInfo;
-
- /* Any info available? */
- if (Examine(FileLock, &FileInfo))
- {
- /* Modification date. */
- Seconds = (FileInfo.fib_Date.ds_Days * 24 * 60 + FileInfo.fib_Date.ds_Minute) * 60 + (FileInfo.fib_Date.ds_Tick) / TICKS_PER_SECOND + GMT_Offset;
-
- /* Take care of the owner bits. */
- if (FileInfo.fib_Protection & FIBF_EXECUTE)
- Mode |= 0100;
-
- if (FileInfo.fib_Protection & (FIBF_WRITE | FIBF_DELETE))
- Mode |= 0200;
-
- if (FileInfo.fib_Protection & FIBF_READ)
- Mode |= 0400;
-
- /* Take care of the group bits. */
- if (!(FileInfo.fib_Protection & FIBF_GRP_EXECUTE))
- Mode |= 0010;
-
- if (!(FileInfo.fib_Protection & FIBF_GRP_WRITE) || !(FileInfo.fib_Protection & FIBF_GRP_DELETE))
- Mode |= 0020;
-
- if (!(FileInfo.fib_Protection & FIBF_GRP_READ))
- Mode |= 0040;
-
- /* Take care of the other bits. */
- if (!(FileInfo.fib_Protection & FIBF_OTR_EXECUTE))
- Mode |= 0001;
-
- if (!(FileInfo.fib_Protection & FIBF_OTR_WRITE) || !(FileInfo.fib_Protection & FIBF_OTR_DELETE))
- Mode |= 0002;
-
- if (!(FileInfo.fib_Protection & FIBF_OTR_READ))
- Mode |= 0004;
- }
-
- UnLock(FileLock);
- }
-
- to_octal(buff, Seconds);
- to_octal(mode, Mode);
- }
- else
- {
- to_octal(buff, getsystime(NULL));
- to_octal(mode, 0000);
- }
-
- /* amiga.lib mysprintf() can't do %lo format, so we do it the hard way */
- /* Yes, octal; ZModem was originally done on Unix, and they like octal there */
-
- mysprintf(p, "%ld %s %s", (v->Fsize < 0) ? 0L : v->Fsize, buff, mode);
-
- /* Send filename packet */
- return zsendfile(v, (short) (p - v->Pktbuf + strlen(p) + 1));
- } /* End of short sendname() */
-
- /**********************************************************
- * short zsendfile(struct Vars *v, short blen)
- *
- * Send the filename packet and see if receiver will accept
- * file
- **********************************************************/
- short zsendfile(struct Vars *v, short blen)
- {
- short c;
-
- while (TRUE)
- {
- v->Txhdr[ZF0] = v->Lzconv; /* Text or Binary mode; from config string */
- v->Txhdr[ZF1] = LZMANAG; /* Default file management mode */
- v->Txhdr[ZF2] = LZTRANS; /* Default file transport mode */
- v->Txhdr[ZF3] = 0;
- zsbhdr(v, ZFILE);
- zsdata(v, blen, ZCRCW);
- sendbuf(v);
- again:
- /* Check for abort from comm program */
- if (v->io.xpr_chkabort && (*v->io.xpr_chkabort) () < 0)
- {
- bfclose(v);
- canit(v); /* Receiver does not respond to ZABORT. */
- return ERROR;
- }
- switch (c = zgethdr(v))
- {
- case ZRINIT:
- goto again;
- case ZCAN:
- case ZCRC:
- case RCDO:
- case TIMEOUT:
- case ZABORT:
- case ZFIN:
- upderr(v, v->Msgbuf);
- return ERROR;
- case ZSKIP: /* Receiver doesn't want this one */
- upderr(v, GetLocaleString(MSG_SKIP_COMMAND_RECEIVED_TXT));
- bfclose(v);
- return c;
- case ZRPOS: /* Receiver wants it; this is starting position */
- bfseek(v, v->Rxpos);
- v->Strtpos = v->Txpos = v->Rxpos;
- if (v->io.xpr_sflush)
- (*v->io.xpr_sflush) ();
- v->Modemcount = 0;
- return zsendfdata(v);
- }
- }
- } /* End of short zsendfile() */
-
- /**********************************************************
- * short zsendfdata(struct Vars *v)
- *
- * Send the file data
- **********************************************************/
- short zsendfdata(struct Vars *v)
- {
- short c, e, blklen, goodbytes = 0;
- USHORT framelen, maxblklen, goodneeded = 512;
-
- /* Figure out max data packet size to send */
- maxblklen = v->ksize;
- if (v->Rxbuflen && maxblklen > v->Rxbuflen)
- maxblklen = v->Rxbuflen;
- blklen = (v->Baud < 1200) ? 256 : v->ksize;
- if (blklen > maxblklen)
- blklen = maxblklen;
-
- /* If an interruption happened, handle it; else keep sending data */
- somemore:
- while (char_avail(v))
- {
- /* Check for another incoming packet while discarding line noise */
- switch (readock(v, 1))
- {
- case CAN:
- case RCDO:
- case ZPAD:
- break;
- default:
- continue;
- }
- waitack:
- switch (c = getinsync(v))
- {
- default:
- upderr(v, GetLocaleString(MSG_TRANSFER_CANCELED_TXT));
- bfclose(v);
- return ERROR;
- case ZSKIP: /* Receiver changed its mind and wants to skip the file */
- bfclose(v);
- return c;
- case ZACK: /* ACK at end of frame; resume sending data */
- break;
- case ZRPOS: /* An error; resend data from last good point */
- blklen >>= 2;
- if (blklen < MINBLOCK)
- blklen = MINBLOCK;
- if (goodneeded < MAXGOODNEEDED)
- goodneeded <<= 1;
- v->xpru.xpru_updatemask = XPRU_ERRORS;
- ++v->xpru.xpru_errors;
- (*v->io.xpr_update) (&v->xpru);
- break;
- case ZRINIT:
- updmsg(v, GetLocaleString(MSG_DONE_TXT));
- return OK;
- }
- }
-
- /* Transmit ZDATA frame header */
- framelen = v->Rxbuflen;
- stohdr(v, v->Txpos);
- zsbhdr(v, ZDATA);
-
- /* Keep sending data packets until finished or interrupted */
- do
- {
- /* Read next chunk of file data */
- c = bfread(v, v->Pktbuf, (long) blklen);
-
- /* Figure out how to handle this data packet */
- if (c < blklen)
- e = ZCRCE; /* If end of file, this is last data packet */
- else if (v->Rxbuflen && (framelen -= c) <= 0)
- e = ZCRCW; /* If end of frame, ask for ACK */
- else
- e = ZCRCG; /* Else tell receiver to expect more data packets */
-
- zsdata(v, c, e); /* Send the packet */
- sendbuf(v);
-
- /* Update comm program status display */
- v->xpru.xpru_updatemask = XPRU_BLOCKS | XPRU_BLOCKSIZE | XPRU_BYTES
- | XPRU_ELAPSEDTIME | XPRU_BLOCKCHECK;
- ++v->xpru.xpru_blocks;
- v->xpru.xpru_blocksize = c;
- v->xpru.xpru_blockcheck = v->Crc32t ? "CRC-32" : "CRC-16";
- v->xpru.xpru_bytes = v->Txpos += c;
- update_rate(v);
- (*v->io.xpr_update) (&v->xpru);
-
- /* If we've been sending smaller than normal packets, see if it's
- * time to bump the packet size up a notch yet
- */
- if (blklen < maxblklen && (goodbytes += c) >= goodneeded)
- {
- blklen <<= 1;
- if (blklen > maxblklen)
- blklen = maxblklen;
- goodbytes = 0;
- }
-
- /* Give comm program its timeslice if it needs one */
- if (v->io.xpr_chkmisc)
- (*v->io.xpr_chkmisc) ();
- /* Check for abort from comm program */
- if (v->io.xpr_chkabort)
- {
- long result = (*v->io.xpr_chkabort) ();
-
- if(result < 0)
- {
- canit(v); /* Receiver does not respond to ZABORT. */
- goto aborted;
- }
- }
- /* If this was last packet in frame, go wait for ACK from receiver */
- if (e == ZCRCW)
- goto waitack;
-
- /*
- * Check if receiver trying to interrupt us; look for incoming packet
- * while discarding line noise
- */
- while (char_avail(v))
- {
- switch (readock(v, 1))
- {
- case CAN:
- case RCDO:
- case ZPAD:
- /* Interruption detected; stop sending and process complaint */
- zsdata(v, 0, ZCRCE);
- sendbuf(v);
- goto waitack;
- }
- }
- }
- while (e == ZCRCG); /* If no interruption, keep sending data packets */
-
- /* Done sending file data; send EOF and wait for receiver to acknowledge */
- while (TRUE)
- {
- updmsg(v, GetLocaleString(MSG_SENDING_EOF_TXT));
- stohdr(v, v->Txpos);
- zsbhdr(v, ZEOF);
- sendbuf(v);
- switch (c = getinsync(v))
- {
- case ZACK:
- continue;
- case ZRPOS:
- goto somemore;
- case ZRINIT:
- updmsg(v, GetLocaleString(MSG_EOF_ACKNOWLEDGED_TXT));
- update_rate(v);
- v->xpru.xpru_updatemask = XPRU_ELAPSEDTIME;
- (*v->io.xpr_update) (&v->xpru);
- return OK;
- case ZSKIP:
- bfclose(v);
- return c;
- default:
- aborted:
- upderr(v, GetLocaleString(MSG_TRANSFER_CANCELED_TXT));
- bfclose(v);
- return ERROR;
- }
- }
- } /* End of short zsendfdata() */
-
- /**********************************************************
- * short getinsync(struct Vars *v)
- *
- * Respond to receiver's complaint, get back in sync with
- * receiver
- **********************************************************/
- short getinsync(struct Vars *v)
- {
- short c;
-
- while (TRUE)
- {
- c = zgethdr(v);
- if (v->io.xpr_sflush)
- (*v->io.xpr_sflush) ();
- v->Modemcount = 0;
- switch (c)
- {
- case ZCAN:
- case ZABORT:
- case ZFIN:
- case RCDO:
- case TIMEOUT:
- upderr(v, v->Msgbuf);
- return ERROR;
- case ZRPOS:
- bfseek(v, v->Rxpos);
- v->Txpos = v->Rxpos;
- mysprintf(v->Msgbuf, GetLocaleString(MSG_RESENDING_FROM_TXT), v->Txpos);
- upderr(v, v->Msgbuf);
- return c;
- case ZSKIP:
- upderr(v, GetLocaleString(MSG_SKIP_COMMAND_RECEIVED_TXT));
- /* fallthrough... */
- case ZRINIT:
- bfclose(v);
- /* fallthrough... */
- case ZACK:
- return c;
- default:
- zsbhdr(v, ZNAK);
- sendbuf(v);
- continue;
- }
- }
- } /* End of short getinsync() */
-
- /**********************************************************
- * void saybibi(struct Vars *v)
- *
- * End of batch transmission; disengage cleanly from receiver
- **********************************************************/
- void saybibi(struct Vars *v)
- {
- while (TRUE)
- {
- stohdr(v, 0L);
- zsbhdr(v, ZFIN);
- sendbuf(v);
- switch (zgethdr(v))
- {
- case ZFIN:
- sendline(v, 'O');
- sendline(v, 'O');
- sendbuf(v);
- /* fallthrough... */
- case ZCAN:
- case RCDO:
- case TIMEOUT:
- return;
- }
- }
- } /* End of void saybibi() */
- /* End of Send.c source */
-